home *** CD-ROM | disk | FTP | other *** search
/ Graphics Plus / Graphics Plus.iso / general / modelers / geomview / source.lha / Geomview / src / bin / warp / common / warp.c < prev    next >
C/C++ Source or Header  |  1993-10-28  |  19KB  |  880 lines

  1. #include <string.h>
  2. #include <sys/types.h>
  3. #include <sys/time.h>
  4. #include <stdio.h>
  5. #include <math.h>
  6. #include <limits.h>
  7. #include "geom.h"
  8. #include "bbox.h"
  9. #include "hpoint3.h"
  10. #include "streampool.h"
  11. #include "transform.h"
  12. #include "transobj.h"
  13. #include "lisp.h"
  14. #include "pointlist.h"
  15. #include "pickfunc.h"
  16. #include "ooglutil.h"
  17. #include "warp.h"
  18. #include "api.h"
  19.  
  20. #define FUDGE 1.e-6
  21.  
  22. static char msg[] = "warp.c";
  23.  
  24. /*
  25.  * WarpPoint
  26.  * A modification of the morphing algorithm found in
  27.  * "Feature Based Image Metamorphosis"
  28.  * by Thaddeus Beier and Shawn Neely
  29.  * SIGGRAPH '92 Conference Proceedings
  30.  */
  31.  
  32. /* scale is used to put the object roughly within the unit cube */
  33. void WarpPoint(HPoint3 *old, HPoint3 *new, WarpZone *wz, int n_wz,
  34.            int step, int totsteps, float scale) {
  35.   HPoint3 dsum, Di, tmp;
  36.   double weightsum;
  37.   double weight, dist;
  38.   int i;
  39.   
  40.   if (totsteps <= 0) 
  41.     if (step == totsteps) step = totsteps = 1;
  42.     else return;
  43.  
  44.   HPt3From(&dsum, 0.0, 0.0, 0.0, 1.0);
  45.   weightsum = 0;
  46.   
  47.   if (new == old) {
  48.     HPt3Copy(old, &tmp);
  49.     old = &tmp;
  50.   }
  51.  
  52.   for (i = 0; i < n_wz; i++) {
  53.     
  54.     HPt3Transform(wz[i].T, old, new);
  55.     Di.x = (new->x - old->x) * scale;
  56.     Di.y = (new->y - old->y) * scale;
  57.     Di.z = (new->z - old->z) * scale;
  58.     Di.w = 0.0;
  59.     
  60.     wz[i].RestLocation.w = 1.0;
  61.     dist = scale * HPt3Distance(old, &wz[i].RestLocation);
  62.  
  63.     /* This is the critical line */
  64.     weight = wz[i].a * pow(M_E, -dist*dist*wz[i].b*wz[i].b);
  65.  
  66.     Di.x *= weight;
  67.     Di.y *= weight;
  68.     Di.z *= weight;
  69.     HPt3Add(&dsum, &Di, &dsum);
  70.     
  71.     weightsum += weight;
  72.   }
  73.   
  74.   if (weightsum > FUDGE) {
  75.     dsum.x /= weightsum;
  76.     dsum.y /= weightsum;
  77.     dsum.z /= weightsum;
  78.     dsum.w = 0.0;  
  79.  
  80.   } else HPt3From(&dsum, 0.0, 0.0, 0.0, 0.0);
  81.  
  82.   dsum.x = ((dsum.x / totsteps) * step) / scale;
  83.   dsum.y = ((dsum.y / totsteps) * step) / scale;
  84.   dsum.z = ((dsum.z / totsteps) * step) / scale;
  85.  
  86.   HPt3Add(old, &dsum, new);
  87.   
  88. }
  89.  
  90. void WarpPointN(HPoint3 *old, HPoint3 *new, int n, WarpZone *wz, int n_wz,
  91.         int step, int totsteps, float scale)
  92. {
  93.   int i;
  94.   
  95.   for (i = 0; i < n; i++)
  96.     WarpPoint(&old[i], &new[i], wz, n_wz, step, totsteps, scale);
  97.   
  98. }
  99.  
  100.  
  101. /* That's it for the heavy-duty stuff that actually does the warping.
  102.  * The rest is just stuff to control the widgets, deal with the pipes, 
  103.  * etc */
  104.  
  105. static WarpZone *def;
  106. static vvec warpZoneList;
  107. static int nextName = 1;
  108.  
  109. static pickInterest = 0;
  110.  
  111. static Pool *standardIn, *standardOut;
  112.  
  113. /* 
  114.  * Stuff to read things from Geomview 
  115.  */
  116. Geom *readTarget() {
  117.   Geom *g;
  118.  
  119.   printf ("(echo { )");
  120.   printf("(write geometry - %s bare)", uiGetTarget());
  121.   printf("(echo \"}\\n\" )");
  122.   fflush(stdout);
  123.  
  124.   g = GeomFLoad(stdin, NULL);
  125.   if (g == NULL) uiError("Unable to find geometry", uiGetTarget(), "");
  126.   return g;
  127. }
  128.  
  129.  
  130. float getScaleNormalization(Geom *g) {
  131.   Geom *bbox;
  132.   HPoint3 min, max;
  133.   float tmp, scale;
  134.  
  135.   bbox = GeomBound(g, TM_IDENTITY);
  136.   BBoxMinMax((BBox *)bbox, &min, &max);
  137.   GeomDelete(bbox);
  138.   scale = max.x - min.x;
  139.   tmp = max.y - min.y;
  140.   scale = (scale > tmp) ? scale : tmp;
  141.   tmp = max.z - min.z;
  142.   scale = (scale > tmp) ? scale : tmp;
  143.   if (scale < FUDGE) {
  144.     uiError("Object", "has size", "zero");
  145.     return 1.0;
  146.   }
  147.   else return 1.0 / scale;
  148. }
  149.     
  150.  
  151. /* 
  152.  * Widget stuff 
  153.  */
  154.  
  155. /* Only WidgetCreatAt() includes the progn stuff */
  156. void WidgetCreateAt(float x, float y, float z) {
  157.   WidgetName newname;
  158.  
  159.   apiFreeze();
  160.   printf("(progn ");
  161.   WIDGET_NAME(newname, nextName++);
  162.   WidgetCreateAtNamed(x, y, z, newname);
  163.   printf(")");
  164.   fflush(stdout);
  165.   apiThaw();
  166. }
  167.  
  168. void WidgetCreateAtNamed(float x, float y, float z,
  169.              const char *name) {
  170.   WarpZone *newzone;
  171.  
  172.   newzone = VVINDEX(warpZoneList, WarpZone, VVCOUNT(warpZoneList)++);
  173.   def = VVINDEX(warpZoneList, WarpZone, 0);
  174.   HPt3From(&newzone->RestLocation, x, y, z, 1.0);
  175.   newzone->a = def->a;
  176.   newzone->b = def->b;
  177.               
  178.   printf("(progn ");
  179.   printf("(geometry %s { INST unit { ", name);
  180.   printf("INST unit : WarpWidgetGeom transform : WarpScaleT ");
  181.   printf(" } transform : %sLocationT } )", name);
  182.   printf("(normalization %s none)", name);
  183.   WidgetLocation(name, x, y, z);
  184.   printf(")");        /* progn */
  185.  
  186.   fflush(stdout);
  187.   
  188.   uiAddWidget(name, VVCOUNT(warpZoneList) - 1);
  189.   uiSetSelectedWidget(VVCOUNT(warpZoneList) - 1);
  190. }
  191.  
  192. void WidgetDelete(const char *name) {
  193.   printf("(delete %s)", name);
  194.   fflush(stdout);
  195. }
  196.  
  197. void WidgetLocation(const char *name, float x, float y, float z) {
  198.   Transform T;
  199.  
  200.   printf("(progn ");
  201.   TmTranslate(T, x, y, z);
  202.   printf("(read transform { define %sLocationT ", name);
  203.   fputtransform(stdout, 1, &T[0][0], 0);
  204.   printf(" } ) ");
  205.   printf("(xform-set %s { ", name);
  206.   fputtransform(stdout, 1, &TM_IDENTITY[0][0], 0);
  207.   printf(" } ) ");
  208.   printf(")");        /* End of (progn) */
  209.   fflush(stdout);
  210.  
  211. }
  212.  
  213. void WidgetGetTransform(const char *name, Transform T) {
  214.  
  215.   printf("(echo \"{  \")");
  216.   printf("(write transform - %s world)", name);
  217.   printf("(echo \"}\\n\" )");
  218.   fflush(stdout);
  219.  
  220.   if (!TransStreamIn(standardIn, NULL, T)) {
  221.     uiError("Unable to find transform for", name, "");
  222.     TmIdentity(T);
  223.   }
  224.  
  225. }
  226.  
  227. void WidgetSetTransform(const char *name, Transform T) {
  228.   printf("(xform-set %s ", name);
  229.   TransStreamOut(standardOut, NULL, T);
  230.   printf(")");
  231.   fflush(stdout);
  232. }
  233.  
  234. void WidgetDeleteAll() {
  235.   int i;
  236.  
  237.   printf("(progn "); 
  238.   for (i = VVCOUNT(warpZoneList) - 1; i > 0; i--) {
  239.     WidgetDelete(uiGetWidgetName(i));
  240.     uiDeleteWidget(i);
  241.   }
  242.   printf(")"); 
  243.   fflush(stdout);
  244.   
  245.   VVCOUNT(warpZoneList) = 1;
  246.   vvtrim(&warpZoneList);
  247.   def = VVINDEX(warpZoneList, WarpZone, 0);
  248.   uiSetSelectedWidget(0); 
  249. }
  250.  
  251. /* Call-backs for lisp functions */
  252.  
  253. #define PICK_YES    "(interest (pick self))"
  254. #define PICK_NO        "(uninterest (pick self))"
  255.  
  256. DEFPICKFUNC("(pick COORDSYS GEOMID G V E F P VI EI FI)",
  257.         coordsys,
  258.         id,
  259.         point, pn,
  260.         vertex, vn,
  261.         edge, en,
  262.         face, fn, 10,
  263.         ppath, ppn, 50,
  264.         vi,
  265.         ei, ein,
  266.         fi,
  267.         {
  268.           if (pn != 4) return Lt;
  269.           
  270.           if (uiGetCreateOnPick() && uiWidgetIndex(id) == -1) {
  271.         if (point.w > FUDGE)
  272.           WidgetCreateAt(point.x / point.w, point.y / point.w,
  273.                  point.z / point.w);
  274.         else /* I'm not really sure that this is right */
  275.           WidgetCreateAt(point.x, point.y, point.z);
  276.           } 
  277.           return Lt;
  278.         })
  279.  
  280. LDEFINE(ack, LVOID, "(ack)")
  281. {
  282.   LDECLARE(("ack", LBEGIN,
  283.         LEND));
  284.   if (!pickInterest) {
  285.     printf(PICK_YES);
  286.     fflush(stdout);
  287.     pickInterest = 1;
  288.   } 
  289.   uiThaw();
  290.   return Lt;
  291. }
  292.  
  293. /* These routines will be sent from other external modules, or the user
  294.  * via the (emodule-transmit) command. */
  295.  
  296. LDEFINE(create_widget, LVOID, "(create-widget (x y z [w]))\n\
  297.     Creates a widget at named location.")
  298. {
  299.   HPoint3 point;
  300.   int pn = 4;
  301.  
  302.   LDECLARE(("create-widget", LBEGIN,
  303.         LHOLD, LARRAY, LFLOAT, &point, &pn,
  304.         LEND));
  305.   if (pn == 3) point.w = 1.0;
  306.   else if (pn != 4) return Lnil;
  307.   WidgetCreateAt(point.x / point.w, point.y / point.w, 
  308.          point.z / point.w);
  309.   return Lt;
  310. }
  311.  
  312. LDEFINE(create_widget_grid, LVOID, 
  313.     "(create-widget-grid [(xdimn ydimn zdimn)])\n\
  314.     Creates a grid of widgets.  If xdimn, ydimn, and zdimn are not \n\
  315.     specified, they are assumed to be the default or the values which \n\
  316.     have been specified on the user interface panel.  If they are \n\
  317.     present, they will replace the values in the user interface panels.")
  318. {
  319.   int dim[3], dimn = 3;
  320.   LDECLARE(("create-widget-grid", LBEGIN,
  321.         LOPTIONAL,
  322.         LHOLD, LARRAY, LINT, dim, &dimn,
  323.         LEND));
  324.   if (dimn != 3) {
  325.     dim[0] = uiGetGridX();
  326.     dim[1] = uiGetGridY();
  327.     dim[2] = uiGetGridZ();
  328.   } else {
  329.     uiSetGridX(dim[0]);
  330.     uiSetGridY(dim[1]);
  331.     uiSetGridZ(dim[2]);
  332.   }
  333.   apiPosition();
  334.   return Lt;
  335. }
  336.  
  337. LDEFINE(delete_widget, LVOID,
  338.     "(delete-widget [name])\n\
  339.     Deletes widgets.  If name is present, deletes only that widget. \n\
  340.     If name is not specified, deletes all widgets.")
  341. {
  342.   int index;
  343.   char *name = NULL;
  344.   LDECLARE(("delete-widget", LBEGIN,
  345.         LOPTIONAL, 
  346.         LSTRING, &name,
  347.         LEND));
  348.   if (name != NULL) {
  349.     index = uiWidgetIndex(name);
  350.     if (index == -1) return Lnil;
  351.     uiSetSelectedWidget(index);
  352.     apiDelete();
  353.   }
  354.   else apiDeleteAll();
  355.   return Lt;
  356. }
  357.   
  358.  
  359. LDEFINE(preview, LVOID, 
  360.     "(preview [name])\n\
  361.     Same as pressing the preview button.  name is the object to warp.\n\
  362.     If name is omitted the default object or the object specified on \n\
  363.     the user interface panel will be used.  If name is specified, it \n\
  364.     will replace the value on the user interface panel.")
  365. {
  366.   char *name = NULL;
  367.   LDECLARE(("preview", LBEGIN,
  368.        LOPTIONAL,
  369.        LSTRING, &name,
  370.        LEND));
  371.   if (name != NULL) uiSetTarget(name);
  372.   apiPreview();
  373.   return Lt;
  374. }
  375.  
  376. LDEFINE(warp, LVOID, "(warp [name])\n\
  377.     Same as pressing the warp button.name is the object to warp.\n\
  378.         If name is omitted the default object or the object specified on \n\
  379.         the user interface panel will be used.  If name is specified, it \n\
  380.         will replace the value on the user interface panel.")
  381. {
  382.   char *name = NULL;
  383.   LDECLARE(("warp", LBEGIN,
  384.        LOPTIONAL,
  385.        LSTRING, &name,
  386.        LEND));
  387.   if (name != NULL) uiSetTarget(name);
  388.   apiWarp();
  389.   return Lt;
  390. }
  391.   
  392.  
  393.  
  394. LDEFINE(exit, LVOID, "(exit)")
  395.   LDECLARE(("exit", LBEGIN,
  396.         LEND));
  397.   apiExit();
  398.   return Lt;
  399. }
  400.  
  401. /* Things implemented in common code to be called by machine-specific
  402.  * code */
  403.  
  404. void apiFreeze() {
  405.   if (pickInterest) {
  406.     printf(PICK_NO);
  407.     fflush(stdout);
  408.     pickInterest = 0;
  409.   } 
  410.   uiFreeze();
  411. }
  412.  
  413. void apiThaw() {
  414.   printf("(echo \"(ack)\\n\")");
  415.   fflush(stdout); 
  416. }
  417.  
  418. void apiTargetChanged() {
  419.   apiUpdateScale();
  420. }
  421.  
  422. Lake *lake;
  423. LObject *lit, *val;
  424.  
  425. void apiInit() {
  426.  
  427.   uiSetTarget(DEF_OBJECT);
  428.  
  429.   uiSetStrengthBounds(MIN_A, MAX_A);
  430.   uiSetSmoothnessBounds(MIN_B, MAX_B);
  431.  
  432.   uiSetSteps(DEF_INT_STEPS);
  433.   uiSetStart(0);
  434.   uiSetEnd(DEF_INT_STEPS);
  435.  
  436.   uiSetPrefix(DEF_PREFIX);
  437.   uiSetPath(DEF_PATH);
  438.  
  439.   uiSetWidgetGeom(DEF_WIDGET_GEOM);
  440.   uiSetWidgetSize(DEF_WIDGET_SIZE);
  441.  
  442.   uiSetGridX(DEF_GRIDX);
  443.   uiSetGridY(DEF_GRIDY);
  444.   uiSetGridZ(DEF_GRIDZ);
  445.  
  446.   VVINIT(warpZoneList, WarpZone, 8);
  447.   def = VVINDEX(warpZoneList, WarpZone, 0);
  448.   HPt3From(&def->RestLocation, 0.0, 0.0, 0.0, 1.0);
  449.   def->a = DEF_A;
  450.   def->b = DEF_B;
  451.   nextName = 1;
  452.   VVCOUNT(warpZoneList) = 1;
  453.   uiAddWidget("default", 0);
  454.   uiSetSelectedWidget(0);
  455.  
  456.   standardIn = PoolStreamTemp(NULL, stdin, 0, NULL);
  457.   standardOut = PoolStreamTemp(NULL, stdout, 1, NULL);
  458.  
  459.   apiUpdateGeom();
  460.   apiUpdateScale();
  461.  
  462.   LInit();
  463.   lake = LakeDefine(stdin, stdout, NULL);
  464.   printf(PICK_YES);
  465.   fflush(stdout);
  466.   pickInterest = 1;
  467.   LDefun("pick", Lpick, Hpick);
  468.   LDefun("ack", Lack, Hack);
  469.  
  470.   LDefun("create-widget", Lcreate_widget, Hcreate_widget);
  471.   LDefun("create-widget-grid", Lcreate_widget_grid, Hcreate_widget_grid);
  472.   LDefun("delete-widget", Ldelete_widget, Hdelete_widget);
  473.   LDefun("preview", Lpreview, Hpreview);
  474.   LDefun("warp", Lwarp, Hwarp);
  475.   LDefun("exit", Lexit, Hexit);
  476.   
  477.   pointlist_init();
  478.  
  479. }
  480.  
  481. int apiCheckPipes() {
  482.   if (async_fnextc(stdin, 0) != NODATA) {
  483.     apiDoPipes();
  484.     return 1;
  485.   } else {
  486.     static struct timeval tenth = { 0, 100000 };
  487.     select(0, NULL, NULL, NULL, &tenth);
  488.     return 0;
  489.   }
  490. }
  491.  
  492. void apiDoPipes() {
  493.   lit = LSexpr(lake);
  494.   val = LEval(lit);
  495.   LFree(lit);
  496.   LFree(val);
  497. }
  498.  
  499. int apiVerifyUI() {
  500.   int bad = 0;
  501.  
  502.   if (!strlen(uiGetTarget())) {
  503.     uiSetTarget(DEF_OBJECT);
  504.     bad = 1;
  505.   }
  506.   if (uiGetSelectedWidget() < 0 || 
  507.       uiGetSelectedWidget() > VVCOUNT(warpZoneList) - 1) {
  508.     uiSetSelectedWidget(0);
  509.     bad = 1;
  510.   }
  511.   if (uiGetSteps() < 0) {
  512.     uiSetSteps(DEF_INT_STEPS);
  513.     bad = 1;
  514.   }
  515.   if (uiGetStart() < 0) {
  516.     uiSetStart(0);
  517.     bad = 1;
  518.   }
  519.   if (uiGetEnd() != uiGetStart() + uiGetSteps()) { 
  520.     uiSetEnd(uiGetStart() + uiGetSteps());
  521.     bad = 1;
  522.   }
  523.   if (!strlen(uiGetPrefix())) {
  524.     uiSetPrefix(DEF_PREFIX);
  525.     bad = 1;
  526.   }
  527.   if (!strlen(uiGetPath())) {
  528.     uiSetPath(DEF_PATH);
  529.     bad = 1;
  530.   }
  531.   if (!strlen(uiGetWidgetGeom())) {
  532.     uiSetWidgetGeom(DEF_WIDGET_GEOM);
  533.     bad = 1;
  534.   }
  535.   if (uiGetWidgetSize() < 0.0) {
  536.     uiSetWidgetSize(DEF_WIDGET_SIZE);
  537.     bad = 1;
  538.   }
  539.   if (uiGetGridX() < 1) {
  540.     uiSetGridX(DEF_GRIDX);
  541.     bad = 1;
  542.   } 
  543.   if (uiGetGridY() < 1) {
  544.     uiSetGridY(DEF_GRIDY);
  545.     bad = 1;
  546.   }
  547.   if (uiGetGridZ() < 1) {
  548.     uiSetGridZ(DEF_GRIDZ);
  549.     bad = 1;
  550.   }
  551.  
  552.   return bad;
  553. }
  554.  
  555. void apiPreview() {
  556.   int n_wz;
  557.   Geom *g;
  558.   int i;
  559.   HPoint3 *points;
  560.   int n_points;
  561.  
  562.   apiFreeze();
  563.   apiVerifyUI();
  564.   
  565.   n_wz = VVCOUNT(warpZoneList) - 1;
  566.   for (i = 1; i < VVCOUNT(warpZoneList); i++)
  567.     WidgetGetTransform(uiGetWidgetName(i), 
  568.                VVINDEX(warpZoneList, WarpZone, i)->T);
  569.   
  570.   if (i == 1) {
  571.     apiThaw();
  572.     return;
  573.   }
  574.  
  575.   g = readTarget();
  576.   if (g == NULL) {
  577.     apiThaw();
  578.     return;
  579.   }
  580.  
  581.   points = PointList_get(g, TM_IDENTITY, POINTLIST_SELF);
  582.   n_points = PointList_length(g);
  583.   WarpPointN(points, points, n_points, VVINDEX(warpZoneList, WarpZone, 1),
  584.          n_wz, 1, 1, getScaleNormalization(g));
  585.   PointList_set(g, POINTLIST_SELF, points);
  586.  
  587.   printf("(geometry preview { ");
  588.   GeomFSave(g, stdout, NULL);
  589.   printf(" } ) ");
  590.   fflush(stdout);
  591.   
  592.   GeomDelete(g);
  593.   OOGLFree(points);
  594.   
  595.   apiThaw();
  596.   
  597. }
  598.  
  599. void apiWarp() {
  600.   WarpZone *wz;
  601.   int n_wz;
  602.   int i;
  603.   Geom *g, *dest;
  604.   HPoint3 *points, *newpoints;
  605.   int n_points;
  606.   int firststep, step, totsteps;
  607.   char buf[512];
  608.   float scale;
  609.   
  610.   apiFreeze();
  611.   
  612.   apiVerifyUI();
  613.   
  614.   n_wz = VVCOUNT(warpZoneList) - 1;
  615.   for (i = 1; i < VVCOUNT(warpZoneList); i++) {
  616.     wz = VVINDEX(warpZoneList, WarpZone, i);
  617.     WidgetGetTransform(uiGetWidgetName(i), wz->T);
  618.     HPt3Transform(wz->T, &wz->RestLocation, &wz->TransLocation);
  619.   }
  620.   
  621.   if (i == 1) {
  622.     apiThaw();
  623.     return;
  624.   }
  625.   
  626.   g = readTarget();
  627.   if (g == NULL) {
  628.     apiThaw();
  629.     return;
  630.   }
  631.   scale = getScaleNormalization(g);
  632.   
  633.   dest = GeomCopy(g);
  634.   
  635.   if (uiGetIntToGV() || uiGetIntToFiles()) {
  636.     firststep = uiGetStart();
  637.     totsteps = uiGetEnd();
  638.     if (uiGetAutoUpdate()) {
  639.       uiSetStart(uiGetStart() + uiGetSteps() + 1);
  640.       uiSetEnd(uiGetEnd() + uiGetSteps() + 1);
  641.     }
  642.   }
  643.   else {
  644.     totsteps = 1;
  645.     firststep = 0;
  646.   }
  647.   
  648.   points = PointList_get(g, TM_IDENTITY, POINTLIST_SELF);
  649.   n_points = PointList_length(g);
  650.   newpoints = OOGLNewNE(HPoint3, n_points, msg);
  651.   bcopy(points, newpoints, n_points * sizeof(HPoint3));
  652.   
  653.   for (step = 1; step <= totsteps; step++) {
  654.     WarpPointN(points, newpoints, n_points,
  655.            VVINDEX(warpZoneList, WarpZone, 1), n_wz, step, totsteps, 
  656.            scale);
  657.     PointList_set(dest, POINTLIST_SELF, newpoints);
  658.     if (uiGetIntToFiles()) {
  659.       sprintf(buf, "%s%s%04d", uiGetPath(), uiGetPrefix(), 
  660.           firststep + step);
  661.       if (GeomSave(dest, buf) == NULL) 
  662.     uiError("Unable to save file", buf, "");
  663.     }
  664.     if (uiGetIntToGV()) {
  665.       if (uiGetRetain()) printf("(new-geometry ");
  666.       else printf("(geometry ");
  667.       printf(" %s { ", uiGetTarget());
  668.       GeomFSave(dest, stdout, NULL);
  669.       printf(" } ) ");
  670.       fflush(stdout);
  671.     }
  672.   }
  673.   
  674.   printf("(progn ");
  675.   
  676.   printf("(geometry %s { ", uiGetTarget());
  677.   GeomFSave(dest, stdout, NULL);
  678.   printf(" } ) ");
  679.   fflush(stdout);
  680.   
  681.   wz = VVINDEX(warpZoneList, WarpZone, 1);
  682.   for (i = 0; i < n_wz; i++) {
  683.     WarpPoint(&wz[i].RestLocation, &wz[i].TransLocation,
  684.           wz, n_wz, 1, 1, scale);
  685.     WidgetLocation(uiGetWidgetName(i+1),
  686.            wz[i].TransLocation.x, wz[i].TransLocation.y,
  687.            wz[i].TransLocation.z);
  688.     WidgetSetTransform(uiGetWidgetName(i+1), TM_IDENTITY);
  689.   }
  690.   for (i = 0; i < n_wz; i++)
  691.     HPt3Copy(&wz[i].TransLocation, &wz[i].RestLocation);
  692.   
  693.   printf(")");        /* End of (progn) */
  694.  
  695.   fflush(stdout);
  696.   
  697.   GeomDelete(g);
  698.   GeomDelete(dest);
  699.   OOGLFree(points);
  700.   OOGLFree(newpoints);
  701.   
  702.   apiThaw();
  703.   
  704. }
  705.  
  706. void apiEdit() {
  707.   int i;
  708.   WarpZone *wz;
  709.  
  710.   i = uiGetSelectedWidget();
  711.   wz = VVINDEX(warpZoneList, WarpZone, i);
  712.   uiSetStrength(wz->a);
  713.   uiSetSmoothness(wz->b);
  714.   uiSetPoint((Point3 *)(&(wz->RestLocation)));
  715.   uiEdit(uiGetWidgetName(i));
  716. }
  717.  
  718. void apiEditSet() {
  719.   int i;
  720.   WarpZone *wz;
  721.  
  722.   i = uiGetSelectedWidget();
  723.   wz = VVINDEX(warpZoneList, WarpZone, i);
  724.   wz->a = uiGetStrength();
  725.   wz->b = uiGetSmoothness();
  726.   uiGetPoint((Point3 *)(&(wz->RestLocation)));
  727.   WidgetLocation(uiGetWidgetName(i), wz->RestLocation.x, wz->RestLocation.y,
  728.          wz->RestLocation.z);
  729. }
  730.  
  731. void apiEditSetAll() {
  732.   int i;
  733.   float a, b;
  734.   a = uiGetStrength();
  735.   b = uiGetSmoothness();
  736.   for (i = 0; i < VVCOUNT(warpZoneList); i++) {
  737.     VVINDEX(warpZoneList, WarpZone, i)->a = a;
  738.     VVINDEX(warpZoneList, WarpZone, i)->b = b;
  739.   }
  740. }
  741.  
  742. void apiEditLocation() {
  743.   int i;
  744.   WarpZone *wz;
  745.  
  746.   i = uiGetSelectedWidget();
  747.   wz = VVINDEX(warpZoneList, WarpZone, i);
  748.   WidgetGetTransform(uiGetWidgetName(i), wz->T);
  749.   HPt3Transform(wz->T, &wz->RestLocation, &wz->TransLocation);
  750.   uiSetPoint((Point3 *)(&(wz->TransLocation)));
  751. }
  752.  
  753. void apiDelete() {
  754.   int i, j;
  755.  
  756.   i = uiGetSelectedWidget();
  757.   if (i < 1) return;
  758.   WidgetDelete(uiGetWidgetName(i));
  759.  
  760.   for (j = i+1; j < VVCOUNT(warpZoneList); j++)
  761.     bcopy(VVINDEX(warpZoneList, WarpZone, j),
  762.       VVINDEX(warpZoneList, WarpZone, j-1), sizeof(WarpZone));
  763.   VVCOUNT(warpZoneList) = VVCOUNT(warpZoneList) - 1;
  764.   uiDeleteWidget(i);
  765.  
  766.   if (i < VVCOUNT(warpZoneList)) uiSetSelectedWidget(i);
  767.   else uiSetSelectedWidget(i-1);
  768.  
  769.   vvtrim(&warpZoneList);
  770.   def = VVINDEX(warpZoneList, WarpZone, 0);
  771. }
  772.  
  773. void apiDeleteAll() {
  774.   apiFreeze(); 
  775.   WidgetDeleteAll();
  776.   apiThaw();
  777. }
  778.  
  779. void apiPosition() {
  780.   int x, y, z, i, j, k;
  781.   Geom *g;
  782.   Geom *bbox;
  783.   HPoint3 min, max;
  784.   float stepx, stepy, stepz;
  785.   WidgetName name;
  786.   
  787.   apiVerifyUI();
  788.   WidgetDeleteAll();
  789.  
  790.   g = readTarget();
  791.   if (g == NULL) return;
  792.   bbox = GeomBound(g, TM_IDENTITY);  
  793.   BBoxMinMax((BBox *)bbox, &min, &max);
  794.  
  795.   x = uiGetGridX();
  796.   y = uiGetGridY();
  797.   z = uiGetGridZ();
  798.   
  799.   if (max.x - min.x < FUDGE) {
  800.     uiSetGridX(1);
  801.     x = 1;
  802.   }
  803.   if (max.y - min.y < FUDGE) {
  804.     uiSetGridY(1);
  805.     y = 1;
  806.   }
  807.   if (max.z - min.z < FUDGE) {
  808.     uiSetGridZ(1);
  809.     z = 1;
  810.   }
  811.   stepx = (max.x - min.x) / (x > 1 ? x-1 : 1);
  812.   stepy = (max.y - min.y) / (y > 1 ? y-1 : 1);
  813.   stepz = (max.z - min.z) / (z > 1 ? z-1 : 1);
  814.  
  815.   printf("(progn ");
  816.   
  817.   for (i = 0; i < x; i++)
  818.     for (j = 0; j < y; j++)
  819.       for (k = 0; k < z; k++) {
  820.     WIDGET_GRIDNAME(name, i, j, k);
  821.     WidgetCreateAtNamed(min.x + stepx * i, min.y + stepy * j,
  822.                 min.z + stepz * k, name);
  823.     
  824.       }
  825.   
  826.   /* Close off progn() statement */
  827.   printf(")");
  828.   fflush(stdout);
  829.   
  830.   GeomDelete(bbox);
  831.   GeomDelete(g);
  832.  
  833. }
  834.  
  835. void apiUpdateGeom() {
  836.   printf("(read geometry { define WarpWidgetGeom < %s })",
  837.      uiGetWidgetGeom());
  838.   fflush(stdout);
  839. }
  840.  
  841. void apiUpdateScale() {
  842.   Transform T;
  843.   float scale;
  844.   Geom *g, *bbox;
  845.   HPoint3 min, max;
  846.   float tmp;
  847.  
  848.   if (uiGetRelativeSize()) {
  849.     g = readTarget();
  850.     if (g == NULL) scale = 1.0;
  851.     else {
  852.       bbox = GeomBound(g, TM_IDENTITY);
  853.       BBoxMinMax((BBox *)bbox, &min, &max);
  854.  
  855.       HPt3Normalize(&min, &min);
  856.       HPt3Normalize(&max, &max);
  857.       scale = max.x - min.x;
  858.       tmp = max.y - min.y;
  859.       if (tmp > scale) scale = tmp;
  860.       tmp = max.z - min.z;
  861.       if (tmp > scale) scale = tmp;
  862.     }
  863.     scale *= uiGetWidgetSize();
  864.   } else scale = uiGetWidgetSize();
  865.  
  866.   TmScale(T, scale, scale, scale);
  867.  
  868.   printf("(read transform { define WarpScaleT ");
  869.   TransStreamOut(standardOut, NULL, T); 
  870.   printf("})");
  871.   fflush(stdout);
  872. }
  873.  
  874. void apiExit() {
  875.   apiDeleteAll();
  876.   exit(0);
  877. }
  878.  
  879.